<?php
class TaxonomyBehavior extends CActiveRecordBehavior
{
    public $name;
    public $taxonomy;
    public $module;
    public $objectAttribute='id';
    public $useActiveField=false;
    
    /**
     * Responds to {@link CActiveRecord::onAfterSave} event.
     * Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
     * @param CModelEvent $event event parameter
     */
    public function afterSave($event)
    {
        $data = array();
        $objectId = $this->getOwner()->{$this->objectAttribute};
        if ($this->useActiveField)
        {
            $data = $this->getOwner()->{$this->name};
            if (! is_array($data) && !is_object($data))
            {
                $data = array((int) $data);
            }
        }
        else
        {
            if (isset($_POST[$this->name]))
            {
                $data = $_POST[$this->name];
                if (! is_array($data) && !is_object($data))
                {
                    $data = array((int) $data);
                }
            }
        }
        //delete old
        $sql = "DELETE FROM ".SITE_TABLE_PREFIX."taxonomy_index t"
              . "\n USING ".SITE_TABLE_PREFIX."taxonomy_term tt, ".SITE_TABLE_PREFIX."taxonomy_vocabulary tv"
              . "\n WHERE tt.id = t.term_id AND tv.id = tt.v_id"
              .(is_numeric($this->taxonomy) ? "\n AND (tv.id = :id)" : "\n AND (tv.alias = :alias)")
              . "\n AND tv.module = :module AND t.object_id = :object_id";
        if (count($data))
        {
            foreach ($data as $index => $val)
            {
                $data[$index] = CPropertyValue::ensureInteger($val);
            }
            $dataString = implode(',', $data);
            $sql .= "\n AND t.term_id NOT IN ({$dataString})";
        }
        $command = TermRelation::model()->getDbConnection()->createCommand($sql);
        if (is_numeric($this->taxonomy))
            $command->bindParam(":id",$this->taxonomy,PDO::PARAM_INT);
        else
            $command->bindParam(":alias",$this->taxonomy,PDO::PARAM_STR);
        $command->bindParam(":module",$this->module,PDO::PARAM_STR);
        $command->bindParam(":object_id",$objectId,PDO::PARAM_INT);
        $command->execute();
        
        //update/create
        if (count($data))
        {
            foreach ($data as $val)
            {
                $relation = TermRelation::model()->findByAttributes(array('object_id'=>$objectId, 'term_id'=>$val));
                if (! is_object($relation))
                {
                    $relation = new TermRelation();
                }
                $relation->object_id = $objectId;
                $relation->term_id = $val;
                if (! $relation->save())
                {
                    Yii::log(CVarDumper::dumpAsString($relation->getErrors()), CLogger::LEVEL_ERROR);
                }
            }
        }
    }
    
    /**
    * find all vocavularies of current object
    * 
    * @param int $state vocabulary state
    * @return array Vocabulary
    */
    public function getVocabularies($state=Vocabulary::STATE_ACTIVE)
    {
        $criteria = new CDbCriteria();
        $criteria->join = "INNER JOIN ".SITE_TABLE_PREFIX."taxonomy_term tt ON tt.v_id = t.id"
                        ."\n INNER JOIN ".SITE_TABLE_PREFIX."taxonomy_index ti ON ti.term_id = tt.id";
        if (is_numeric($this->taxonomy))
            $criteria->compare('t.id', $this->taxonomy);
        else
            $criteria->compare('t.alias', $this->taxonomy);
        $criteria->compare('t.module', $this->module);
        $criteria->compare('t.state', $state);
        $objectId = (int) $this->getOwner()->{$this->objectAttribute};
        $criteria->compare('ti.object_id', $objectId);
        return Vocabulary::model()->findAll($criteria);
    }
    
    /**
    * get all terms of current object
    * 
    * @param int $vstate vocabulary state
    * @param int $state term state
    * @return array Term
    */
    public function getTerms($vstate=Vocabulary::STATE_ACTIVE, $state=Term::STATE_ACTIVE)
    {
        $criteria = new CDbCriteria();
        $criteria->join = "INNER JOIN ".SITE_TABLE_PREFIX."taxonomy_vocabulary tv ON tv.id = t.v_id"
                        ."\n INNER JOIN ".SITE_TABLE_PREFIX."taxonomy_index ti ON ti.term_id = t.id";
        if (is_numeric($this->taxonomy))
            $criteria->compare('tv.id', $this->taxonomy);
        else
            $criteria->compare('tv.alias', $this->taxonomy);
        $criteria->compare('tv.module', $this->module);
        $criteria->compare('tv.state', $vstate);
        $criteria->compare('t.state', $state);
        $objectId = (int) $this->getOwner()->{$this->objectAttribute};
        if ($objectId)
            $criteria->compare('ti.object_id', $objectId);
        return Term::model()->findAll($criteria);
    }
    
    /**
    * find object_id by term
    * 
    * @param string $module
    * @param string $taxonomy
    * @param string|int|array $term
    * @return array 
    */
    public function findObjectByTerm($module, $taxonomy, $term=null)
    {
        $condition = 'tv.module = :module AND (tv.id = :name)';
        $params = array(':module'=>$module,':name'=>$taxonomy);
        if ($term !== null)
        {
            if (is_array($term))
            {
                foreach ($term as $index => $val)
                {
                    $term[$index] = $this->getOwner()->getDbConnection()->quoteValue($val);
                }
                $term = implode(',', $term);
                $condition .= ' AND (tt.id IN ('.$term.'))';
            }
            else
            {
                $condition .= ' AND (tt.id = :term)';
                $params[':term'] = $term;
            }
        }
        /** @var CDbCommand */
        $command = $this->getOwner()->getDbConnection()->createCommand();
        return $command->select('ti.*')
            ->from(SITE_TABLE_PREFIX.'taxonomy_index ti')
            ->join(SITE_TABLE_PREFIX.'taxonomy_term tt', 'tt.id=ti.term_id')
            ->join(SITE_TABLE_PREFIX.'taxonomy_vocabulary tv', 'tv.id=tt.v_id')
            ->where($condition, $params)
            ->order('ti.ordering')
            ->queryAll();
    }
    
    /**
    * add scope filter object by  terms
    * 
    * @param string $module
    * @param string $taxonomy
    * @param string|int|array $term
    * @return CActiveRecord
    */
    public function term($module, $taxonomy, $term=null)
    {
        static $count;
        if ($count === null) $count=1;
        else $count++;
        $suffix = '_'.$count;
        $condition = 'tv'.$suffix.'.module = :module'.$suffix;
        $params = array(':module'.$suffix=>$module);
        if (is_numeric($taxonomy))
        {
            $condition .= ' AND (tv'.$suffix.'.id = :id'.$suffix.')';
            $params[':id'.$suffix] = $taxonomy;
        }
        else
        {
            $condition .= ' AND (tv'.$suffix.'.alias = :alias'.$suffix.')';
            $params[':alias'.$suffix] = $taxonomy;
        }
        if ($term !== null)
        {
            if (is_array($term))
            {
                $termId = array();
                $termAlias = array();
                foreach ($term as $index => $val)
                {
                    if (is_numeric($val))
                        $termId[$index] = $this->getOwner()->getDbConnection()->quoteValue($val);
                    else
                        $termAlias[$index] = $this->getOwner()->getDbConnection()->quoteValue($val);
                }
                if (count($termId))
                {
                    $termId = implode(',', $termId);
                    $condition .= ' AND (tt'.$suffix.'.id IN ('.$termId.'))';
                }
                if (count($termAlias))
                {
                    $termAlias = implode(',', $termAlias);
                    $condition .= ' AND (tt'.$suffix.'.alias IN ('.$termAlias.'))';
                }
            }
            else
            {
                if (is_numeric($term))
                {
                    $condition .= ' AND (tt'.$suffix.'.id = :term'.$suffix.')';
                    $params[':term'.$suffix] = $term;
                }
                else
                {
                    $condition .= ' AND (tt'.$suffix.'.alias = :term'.$suffix.')';
                    $params[':term'.$suffix] = $term;
                }
            }
        }
        /** @var CDbCommand */
        $command = $this->getOwner()->getDbConnection()->createCommand();
        $condition = $command->select('ti'.$suffix.'.object_id')
            ->from(SITE_TABLE_PREFIX.'taxonomy_index ti'.$suffix)
            ->join(SITE_TABLE_PREFIX.'taxonomy_term tt'.$suffix, 'tt'.$suffix.'.id=ti'.$suffix.'.term_id')
            ->join(SITE_TABLE_PREFIX.'taxonomy_vocabulary tv'.$suffix, 'tv'.$suffix.'.id=tt'.$suffix.'.v_id')
            ->where($condition, $params)
            ->text;
        
        $criteria = new CDbCriteria();
        $criteria->condition = 't.id IN ('.$condition.')';
        $criteria->params = $params;
        /** @var CDbCriteria*/
        $this->getOwner()->getDbCriteria()->mergeWith($criteria);
        return $this->getOwner();
    }
}
